package me.keiwu.pub.util;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import me.keiwu.pub.data.ConfigType;
import me.keiwu.pub.data.GlobalConst;
import me.keiwu.pub.data.service.UserInfoBean;
import me.keiwu.pub.data.service.UserMiscBean;
import me.keiwu.pub.data.wx.WXSessionData;
import me.keiwu.pub.util.redis.RedisUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * Created by kei on 24/11/2017.
 */
@Component
public class CacheUtil {

    private static final Logger logger = LoggerFactory.getLogger(CacheUtil.class);


    @Autowired
    private RedisUtil redisUtil;


    public void setLoginUserInfo(long userId, UserInfoBean userInfo) {
        redisUtil.set(GlobalConst.LOGIN_USER_PREFIX + userId, JSON.toJSONString(userInfo), GlobalConst.EXPIRED_TWO_HOURS_SECONDS);
    }

    public void setLoginUserInfo(long userId, String userInfo) {
        redisUtil.set(GlobalConst.LOGIN_USER_PREFIX + userId, userInfo, GlobalConst.EXPIRED_TWO_HOURS_SECONDS);
    }

    public UserInfoBean getLoginUserInfo(long userId) {
        String info = redisUtil.get(GlobalConst.LOGIN_USER_PREFIX + userId);
        if (StringUtils.isBlank(info)) return null;
        return JSON.parseObject(info, UserInfoBean.class);
    }

    public void cleanUserInfo(long userId) {
        redisUtil.del(GlobalConst.LOGIN_USER_PREFIX + userId);
    }



    public void setConfig(int configType, String config) {
        redisUtil.set(GlobalConst.CONFIG_PREFIX + configType, config);
    }
    public <T> T getConfig(ConfigType configType, Class<T> claz) {
        String config = redisUtil.get(GlobalConst.CONFIG_PREFIX + configType.getType());
        if (StringUtils.isBlank(config)) return null;
        return JSON.parseObject(config, claz);
    }


    public void setWxAccessToken(String appId, String accessToken, int expiredSecs) {
        String key = GlobalConst.WX_ACCESS_TOKEN_PREFIX + appId;
        redisUtil.set(key, accessToken, expiredSecs);
    }

    public String getWxAccessToken(String appId) {
        String key = GlobalConst.WX_ACCESS_TOKEN_PREFIX + appId;
        return redisUtil.get(key);
    }



    public void setUserMisc(long userId, String misc) {
        String key = GlobalConst.USER_MISC_PREFIX + userId;
        redisUtil.set(key, misc, GlobalConst.EXPIRED_TWO_HOURS_SECONDS);
    }
    public List<UserMiscBean> getUserMisc(long userId) {
        String key = GlobalConst.USER_MISC_PREFIX + userId;
        String misc = redisUtil.get(key);
        if (StringUtils.isBlank(misc)) return null;
        return JSON.parseArray(misc, UserMiscBean.class);
    }



    public void setWXSession(long userId, WXSessionData session) {
        String key = GlobalConst.WX_SESSION_PREFIX + userId;
        redisUtil.set(key, JSON.toJSONString(session), GlobalConst.EXPIRED_TWO_HOURS_SECONDS);
    }
    public void setWXSession(long userId, String session) {
        String key = GlobalConst.WX_SESSION_PREFIX + userId;
        redisUtil.set(key, session, GlobalConst.EXPIRED_TWO_HOURS_SECONDS);
    }
    public WXSessionData getWXSession(long userId) {
        String key = GlobalConst.WX_SESSION_PREFIX + userId;
        String session = redisUtil.get(key);
        if (StringUtils.isBlank(session)) return null;
        return JSON.parseObject(session, WXSessionData.class);
    }


    /**
     * 捐赠步数的
     */
    public void incrTotalDonateSteps(int donateSteps) {
        redisUtil.incrBy(GlobalConst.TOTAL_DONATE_STEP_KEY, donateSteps);
    }
    public long getTotalDonateSteps() {
        String value = redisUtil.get(GlobalConst.TOTAL_DONATE_STEP_KEY);
        if (StringUtils.isBlank(value)) return 0;
        return Long.valueOf(value);
    }

    public void incrTotalDonateUsers() {
        redisUtil.incr(GlobalConst.TOTAL_DONATE_USERS_KEY);
    }
    public long getTotalDonateUsers() {
        String value = redisUtil.get(GlobalConst.TOTAL_DONATE_USERS_KEY);
        if (StringUtils.isBlank(value)) return 0;
        return Long.valueOf(value);
    }

    public void setUserDonateSteps(long userId, int donateSteps) {
        redisUtil.set(GlobalConst.USER_DONATE_STEP_PREFIX + userId, "" + donateSteps, GlobalConst.DONATE_STEP_EXPIRED_SECONDS);
    }
    public int getUserDonateSteps(long userId) {
        String value = redisUtil.get(GlobalConst.USER_DONATE_STEP_PREFIX + userId);
        if (StringUtils.isBlank(value)) return 0;
        return Integer.valueOf(value);
    }

//    public void clearDonate() {
//        redisUtil.del(GlobalConst.TOTAL_DONATE_STEP_KEY);
//        redisUtil.del(GlobalConst.TOTAL_DONATE_USERS_KEY);
//
//        // shard
//        String shardKey = GlobalConst.USER_DONATE_STEP_PREFIX;
//        Set<String> keySet = redisUtil.shardKeys(shardKey, shardKey + "*");
//        if (keySet == null) return;
//        logger.info("resetDonate keySet.size={}", keySet.size());
//        keySet.forEach(key -> redisUtil.shardDel(shardKey, key));
//    }


    /**
     * 探索
     */
    public void recordStealUser(long userId, Long stealId) {
        List<Long> stealUsers = new ArrayList<>();
        String ids = this.redisUtil.get(GlobalConst.EXPLORE_STEAL_USERS_PREFIX + userId);
        if (StringUtils.isNotBlank(ids)) {
            stealUsers = JSON.parseArray(ids, Long.class);
        }
        stealUsers.add(stealId);
        this.redisUtil.set(GlobalConst.EXPLORE_STEAL_USERS_PREFIX + userId, JSON.toJSONString(stealUsers), this.getExpiredSecs());
    }
    public boolean checkCanSteal(long userId, Long stealId) {
        String ids = this.redisUtil.get(GlobalConst.EXPLORE_STEAL_USERS_PREFIX + userId);
        if (StringUtils.isBlank(ids)) return true;
        return !JSON.parseArray(ids, Long.class).contains(stealId);
    }

    public void recordRefreshUsers(long userId, List<Long> userIds) {
        List<Long> idList = this.getRefreshUsers(userId);
        idList.addAll(userIds);
        int expiredSecs = this.getExpiredSecs();
        this.redisUtil.set(GlobalConst.EXPLORE_REFRESH_USERS_PREFIX + userId, JSON.toJSONString(idList), expiredSecs);
    }
    public List<Long> getRefreshUsers(long userId) {
        String ids = this.redisUtil.get(GlobalConst.EXPLORE_REFRESH_USERS_PREFIX + userId);
        if (StringUtils.isBlank(ids)) return Lists.newArrayList();
        return JSON.parseArray(ids, Long.class);
    }



    private int getExpiredSecs() {
        return DateUtil.getUnixTime(DateUtil.getDayStart(DateUtil.addDays(new Date(), 1))) - DateUtil.getUnixTime();
    }


    /**
     * 排行榜
     */
    public Long addRankMember(String member, double score) {
        return this.addRankMember(GlobalConst.RANK_LIST_KEY, member, score);
    }
    public Long addRankMember(String key, String member, double score) {
        return this.redisUtil.zadd(key, score, member);
    }

    public Set<String> getRank(long start, long end) {
        return this.getRank(GlobalConst.RANK_LIST_KEY, start, end);
    }
    public Set<String> getRank(String key, long start, long end) {
        return this.redisUtil.zrevrange(key, start, end);
    }

    public Double getRankScore(long userId) {
        return this.getRankScore(GlobalConst.RANK_LIST_KEY, userId);
    }
    public Double getRankScore(String key, long userId) {
        return this.redisUtil.zscore(key, userId + "");
    }

    public Long getUserRank(long userId) {
        return this.getUserRank(GlobalConst.RANK_LIST_KEY, userId);
    }
    public Long getUserRank(String key, long userId) {
        return this.redisUtil.zrevrank(key, userId + "");
    }

    public void clearRank() {
        this.clearRank(GlobalConst.RANK_LIST_KEY);
    }
    public void clearRank(String key) {
        this.redisUtil.del(key);
    }

    public String getGroupRankKey(String openGroupId) {
        return GlobalConst.GROUP_RANK_KEY + openGroupId;
    }


    /**
     * 模版消息
     * @param userId
     */
    public void recordTemplateMsgForSteal(Long userId) {
        this.redisUtil.set(GlobalConst.EXPLORE_STEAL_USERS_NOTICED_PREFIX + userId,"true",this.getExpiredSecs());
    }
    public boolean canTemplateMsgForSteal(Long userId) {
        String ids = this.redisUtil.get(GlobalConst.EXPLORE_STEAL_USERS_NOTICED_PREFIX + userId);
        return StringUtils.isBlank(ids);
    }

    public void recordTemplateMsgForResult(Long userId) {
        this.redisUtil.set(GlobalConst.CHALLENGE_RESULT_USERS_NOTICED_PREFIX + userId,"true",this.getExpiredSecs());
    }
    public boolean canTemplateMsgForResult(Long userId) {
        String ids = this.redisUtil.get(GlobalConst.CHALLENGE_RESULT_USERS_NOTICED_PREFIX + userId);
        return StringUtils.isBlank(ids);
    }

    public void recordTemplateMsgForChallengeInvite(Long userId, String tail) {
        String key = GlobalConst.CHALLENGE_INVITE_USER_NOTICED_PREFIX + userId + tail;

        this.redisUtil.set(key,"true" ,this.getExpiredSecs());
    }

    public boolean canTemplateMsgForChallengeInvite(Long userId, String tail) {
        String ids = this.redisUtil.get(GlobalConst.CHALLENGE_INVITE_USER_NOTICED_PREFIX + userId + tail);
        return StringUtils.isBlank(ids);
    }

    public Long clearTmpMsgRecord(String redisKey){
        return this.redisUtil.del(redisKey);
    }

    public void recordUserAwardForChallenge(Long userId, Long challengeId) {
        List<Long> awardChallenges = new ArrayList<>();
        String ids = this.redisUtil.get(GlobalConst.CHALLENGE_AWARD_USERS_PREFIX + userId);
        if (StringUtils.isNotBlank(ids)) {
            awardChallenges = JSON.parseArray(ids, Long.class);
        }
        awardChallenges.add(challengeId);
        this.redisUtil.set(GlobalConst.EXPLORE_STEAL_USERS_PREFIX + userId, JSON.toJSONString(awardChallenges), this.getExpiredSecs());
    }
    public boolean isAwardChallenge(Long userId, Long challengeId) {
        String ids = this.redisUtil.get(GlobalConst.EXPLORE_STEAL_USERS_PREFIX + userId);
        if (StringUtils.isBlank(ids)) return false;
        return JSON.parseArray(ids, Long.class).contains(challengeId);
    }

}
